package source;

/**
 * Entity is the abstract base class for units and structures. It establishes the
 * shared attributes for its subclasses, such as:
 * <ul>
 * <li> Offensive damage - 	int value to indicate the units 'attack' power
 * <li> Defensive damage - 	int value to indicate the damage the unit inflicts to
 * 						   	an attacking unit.
 * <li> Armor -				int value to represent the damage the unit will absorb 
 * 							before it's health decreases.
 * <li> Health -			int value to show the units current state; when this 
 * 							reaches zero, the entity is destroyed
 * <li> Upkeep -			the resources required to keep the entity in play
 * <li> View Distance -		int value to represent the distance in tiles the entity
 * 							can see.
 * <li> Position -			the current tile the entity resides on
 * <li> Player -			the PlayerStatus object that owns this entity
 * </ul><p>
 * Entities interact with tiles and have no direct interaction with any other
 * object in the game system.
 * 
 * @author Sean Larson
 *
 */

public abstract class Entity {
	// TODO add upkeep values; how to represent the value? int?
	
	/**
	 * EntityType is a basic enumeration used to represent the type of entity;
	 * Can be either an unit or structure, never both.
	 * @author Sean Larson
	 *
	 */
	public enum EntityType	{
		UNIT, STRUCTURE;
	}
	
	private final EntityType type;	// stores entity type;
	private Tile position;				// Tile entity resides on;
	private int maxHP, HP;			// represent entities state;
	private int oDamage, dDamage, armor, upkeep;		
										// values used when entity is involved in
										// combat;
	private int viewDistance;			// # of Tiles unit can view in any direction
	private PlayerStatus player;
	private Stats stats;
	
	private String picture;

	public Entity(){
	this.type = EntityType.STRUCTURE;
	}

	public Entity(EntityType eType, Stats s)	{
		this.type = eType;
		this.armor = s.armor();
		this.oDamage = s.oDamage();
		this.dDamage = s.dDamage();
		this.HP = s.health();
		this.maxHP = s.health();
		this.viewDistance = s.viewDistance();
		this.position = s.position();
		this.player = s.player();
		this.stats=s;
		this.picture = s.picture();
		this.upkeep = s.upkeep();
	}
	
	/**
	 * returns the type of this object
	 * @return 	<code>UNIT</code> if the entity is a unit type;
	 * 			<code>STRUCTURE</code> if the entity is a structure type
	 */
	public EntityType getType() {
		return this.type;
	}
	
	public String getPicture(){
		return picture;
	}
	
	/**
	 * returns the units current health status
	 * @return int value representing current health of the entity
	 */
	public void setPlayer(PlayerStatus player){
		this.player = player;
	}

	public int getCurrentHP() {
		return this.HP;
	}
	
	public int getUpkeep() {
		return this.upkeep;
	}
	
	/**
	 * returns maximum health for this entity
	 * @return int value representing the maximum health of the entity
	 */
	public int getMaxHP() {
		return this.maxHP;
	}
	
	/**
	 * returns entity's view distance as a number of Tiles
	 * @return int value representing the number of Tiles the unit can see in any
	 * 				direction
	 */
	public int getViewDistance() {
		return this.viewDistance;
	}
	/**
	 * to be used by the Army class to change view distance when new Units are added
	 * @param newView the new view for this object
	 */
	protected void setViewDistance(int newView) {
		this.viewDistance = newView;
	}
	
	/**
	 * gives the entity's attack power as an integer value. Map will determine how
	 * to use the value to pass damage to another Entity.
	 * @return int value representing the offensive power of the Entity
	 */
	public int getAttackPower() {
		return this.oDamage;
	}
	
	/**
	 * gives the entity's defensive attack power. Map uses the value as necessary
	 * during combat.
	 * @return int value for the Entity's defensive attack power.
	 */
	public int getDefensivePower() {
		return this.dDamage;
	}
	
	/**
	 * gives the entity's armor value. Map uses the value during combat.
	 * @return int value for this Entity's armor.
	 */
	public int getArmor() {
		return this.armor;
	}
	
	/**
	 * The entity receives damage as determined by Map. If health state drops to
	 * zero, then the entity is considered destroyed and the method returns false.
	 * @param damage - the amount of damage inflicated upon this entity
	 * @return true if the entity survived the damage (health did not reach zero);
	 * false if the entity was destroyed
	 */
	public boolean takeDamage(int damage) {
		this.HP = this.HP - damage;
		if (this.HP > 0) return true;	// entity survived! notify the caller
		else return false;				// entity kicked the bucket... notify next of
										// kin
			
	}
	
	public PlayerStatus getPlayer() {
		return this.player;
	}
	
	/**
	 * Accessor method to get the entities position on the map.
	 * @return the Tile on which this currently resides
	 */
	public Tile getPosition() {
		return this.position;
	}
	
	
	/**
	 * Mutator method to change the Tile that the unit resides on
	 * @param newPosition - Tile to move the entity to
	 */
	public void setPosition(Tile newPosition) {
		this.position = newPosition;
	}
	
	/**
	 * Mutator method for the Entities current health. Passed an int value to
	 * add to the HP attribute. If this will raise the Entities health above the
	 * maximum, sets HP to maximum. If the Unit's health is now at max, return
	 * true, otherwise return false
	 * @param HP int - the amount to add to current HP
	 * @return boolean - true if Entity is fully healed; false otherwise
	 */
	protected boolean heal(int HP) {
		this.HP += HP;
		if (this.HP > this.maxHP) this.HP = this.maxHP;
		if (this.HP == this.maxHP) return true;
		else return false;
	}

	public void setAttackPower(int AttackPower){
		this.oDamage = AttackPower;
	}

	public void setDefensivePower(int DefensivePower){
		this.dDamage = DefensivePower;
	}

	public void setCurrentHP(int hp){
		this.HP = hp;
	}

	public void setMaxHP(int hp){
		this.maxHP = hp;
	}

	/**
	 * This abstract operation will be used by the subclasses to reset any attributes
	 * (such as movement) that refresh at the start of every turn.
	 * <p>
	 * Should return true if the entity successfully reset it's values.
	 * False if an error occured.
	 * <p>
	 * ??? Should exception be thrown in place of boolean return value ???
	 */
	abstract public boolean newTurn();
	
	/**
	 * This Entity has been destroyed. PlayerStatus and Tile are informed to 
	 * remove the Entity from their references.
	 * Called by subclasses of Entity
	 * @return true if successful; false otherwise
	 */
	public boolean destroy() {
		this.position = null;
		this.player = null;
		return true;
	}
	
	/**
	 * Accessor method for the String that represents the display for this
	 * Entity
	 * @return String - represets the picture to display for this Unit
	 */
}
